package masterjava.common.xml;

import masterjava.common.logging.MasterLogger;
import org.xml.sax.SAXException;

import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.PropertyException;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.io.Writer;
import java.net.URL;


/**
 * Marshalling/Unmarshalling JAXB helper
 *
 * @author Grigory Kislin
 */
public class JaxbParser {

    private static final MasterLogger LOGGER = MasterLogger.get(JaxbParser.class);

    protected JaxbMarshaller jaxbMarshaller;
    protected JaxbUnmarshaller jaxbUnmarshaller;
    protected Schema schema;
    private static final SchemaFactory SCHEMA_FACT = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);


    public JaxbParser(Class... classesToBeBound) {
        try {
            init(JAXBContext.newInstance(classesToBeBound));
        } catch (JAXBException e) {
            throw LOGGER.getIllegalStateException("JAXBContext coudn't be initialized", e);
        }
    }

    public JaxbParser(String context) {
        try {
            init(JAXBContext.newInstance(context));
        } catch (JAXBException e) {
            throw LOGGER.getIllegalStateException("JAXBContext coudn't be initialized", e);
        }
    }

    private void init(JAXBContext ctx) throws JAXBException {
        jaxbMarshaller = new JaxbMarshaller(ctx);
        jaxbUnmarshaller = new JaxbUnmarshaller(ctx);
    }

    public void setSchema(URL schemaUrl) throws SAXException {
        schema = SCHEMA_FACT.newSchema(schemaUrl);
        jaxbUnmarshaller.setSchema(schema);
        jaxbMarshaller.setSchema(schema);
    }

    public void validate(String str) throws IOException, SAXException {
        schema.newValidator().validate(new StreamSource(new StringReader(str)));
    }

    public void setMarshallerProperty(String prop, Object value) throws PropertyException {
        jaxbMarshaller.setProperty(prop, value);
    }

    public Object unmarshal(Reader reader) throws JAXBException {
        return jaxbUnmarshaller.unmarshal(reader);
    }

    public Object unmarshal(String str) throws JAXBException {
        return jaxbUnmarshaller.unmarshal(str);
    }

    public Object unmarshalElement(Reader reader) throws JAXBException {
        return jaxbUnmarshaller.unmarshalElement(reader);
    }

    public Object unmarshalElement(String str) throws JAXBException {
        return jaxbUnmarshaller.unmarshalElement(str);
    }

    public synchronized String marshal(Object instance) throws JAXBException {
        return jaxbMarshaller.marshal(instance);
    }

    public void marshal(Object instance, Writer writer) throws JAXBException {
        jaxbMarshaller.marshal(instance, writer);
    }
}
